#include <ESP8266WiFi.h>
#include <OneWire.h>
#include <DS18B20.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <OLED.h>
#include <ArduinoOTA.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPClient.h>
// wifi
const char* ssid     = "wifi";
const char* password = "wifipassword";
// DS18B20
#define ONE_WIRE_BUS 2
DS18B20 ds(ONE_WIRE_BUS);
// relay
#define OPEN_PIN 14
#define CLOSE_PIN 12
bool ISOPEN = false;
// mqtt
const char MqttServer[] = "10.0.2.11";
const char TOPIC[] = "domoticz/in";
WiFiClient espClient;
PubSubClient client(espClient);
// oled
OLED display(4, 5);
// ota
bool ISOTA = false;
// server
ESP8266WebServer server(80);
// client
HTTPClient http;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(OPEN_PIN, OUTPUT);
  pinMode(CLOSE_PIN, OUTPUT);
  digitalWrite(OPEN_PIN, LOW);
  digitalWrite(CLOSE_PIN, LOW);
  setWifi();
  display.begin();
  client.setServer( MqttServer, 1883 );
  ota();
  setHttpServer();
}

void loop() {
  // put your main code here, to run repeatedly:
  server.handleClient();
  if(ISOTA){
    display.print("OTA...", 4, 5);
    ArduinoOTA.handle();
  } else{
   if (!client.connected()) {
      reconnect();
    }
    client.loop();
    changRelay();
    delay(2000);
  }
}


void setWifi(){
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

// mqtt reconnect
void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect("ESP8266Client")) {
      Serial.println("connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(1000);
    }
  }
}

void changRelay(){
  Serial.println(ds.getTempC());
  float temp = ds.getTempC();
  publishTemp(temp);
  updateOled(temp);
  if(temp >= 42 && !ISOPEN) {
    http.begin("http://10.0.2.200/update?action=close");
    http.GET();
    http.end();
    digitalWrite(OPEN_PIN, HIGH);
    delay(15000);
    ISOPEN = true;
    digitalWrite(OPEN_PIN, LOW);
  } else if (temp < 40 && ISOPEN) {
    http.begin("http://10.0.2.200/update?action=open");
    http.GET();
    http.end();
    digitalWrite(CLOSE_PIN, HIGH);
    delay(15000);
    ISOPEN = false;
    digitalWrite(CLOSE_PIN, LOW);
  }
}

void publishTemp(float temp){
  String payload = "{";
  payload += "\"idx\": 4,";
  payload += "\"command\":\"udevice\",";
  payload += "\"nvalue\": 0,";
  payload += "\"svalue\":";
  payload += "\"";
  payload += temp;
  payload += "\"";
  payload += "}";
  char attributes[100];
  payload.toCharArray( attributes, 100 );
  client.publish(TOPIC, attributes);
}

void updateOled(float temp){
  char c[10];
  dtostrf(temp,2,2,c);
  display.print(c, 4, 5);
}

void ota(){
  ArduinoOTA.onStart([]() {
    display.clear();
    Serial.println("Start");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {nb
    char c[10];
    float p = progress / (total / 100);
    dtostrf(p,2,0,c);
    display.print(c, 4, 7);
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });
  ArduinoOTA.begin();
}

void setHttpServer(){
  server.on("/ota", [](){
    if (server.hasArg("action")){
      if(server.arg("action") == "open") {
        ISOTA = true;
        server.send(200, "text/plain", "start ota update");
      } else if(server.arg("action") == "close"){
        ISOTA = false;
        server.send(200, "text/plain", "stop ota update");
      }
    }
  });
  server.begin();
}
